<?php /* УТФ-8:fix */

class SPIcontroller__validator extends SPIcontroller__dummy
{
    public function open()
    {
        return new SPIcontroller__validator__thread;
    }
}

class SPIcontroller__validator__thread
{
    private $rules = array();
    private $setnull_by_fixvalue = array();
    private $callback_funcs = array();

    public function add_rule( $key, $type )
    {
        if( preg_match( '/^([a-z]+)(.*)$/u', $type, $matches ) == 0 )
        {
            trigger_error( 'Wrong validator rule type ('.$type.') for key ('.$key.')', E_USER_WARNING );
            return false;
        }

        $type = $matches[1];
        $type_attrs = $matches[2];

        $rule_attrs = array();
        $rule_attrs['type'] = $type;

        switch( $type )
        {
            case 'integer':
            {
                if( preg_match( '/\[([0-9-]*):([0-9-]*)\]/u', $type_attrs, $matches ) > 0 )
                {
                    $rule_attrs['min'] = $matches[1] == '' ? null : (int) $matches[1];
                    $rule_attrs['max'] = $matches[2] == '' ? null : (int) $matches[2];
                }
                break;
            }

            case 'float':
            {
                if( preg_match( '/\[([.0-9-]*):([.0-9-]*)\]/u', $type_attrs, $matches ) > 0 )
                {
                    $rule_attrs['min'] = $matches[1] == '' ? null : (float) $matches[1];
                    $rule_attrs['max'] = $matches[2] == '' ? null : (float) $matches[2];
                }
                break;
            }

            case 'string':
            {
                if( preg_match( '/\[([0-9]*):([0-9]*)\]/u', $type_attrs, $matches ) > 0 )
                {
                    $rule_attrs['min_length'] = $matches[1] == '' ? null : (int) $matches[1];
                    $rule_attrs['max_length'] = $matches[2] == '' ? null : (int) $matches[2];
                }
                elseif( strtolower( $type_attrs ) == ':exteditorclean' )
                {
                    $rule_attrs['is_exteditor_clean'] = true;
                }
                break;
            }

            case 'select':
            {
                $rule_attrs['allow_variants'] = (array) func_get_arg(2);
                break;
            }

            case 'multiselect':
            {
                $rule_attrs['allow_variants'] = func_get_arg(2);

                $limits = func_num_args() >= 4 ? (string) func_get_arg(3) : '';

                if( preg_match( '/^\[([.0-9-]*):([.0-9-]*)\]/u', $limits, $matches ) > 0 )
                {
                    $rule_attrs['min_count'] = $matches[1] == '' ? null : (float) $matches[1];
                    $rule_attrs['max_count'] = $matches[2] == '' ? null : (float) $matches[2];
                }
                break;
            }

            case 'url':
            case 'null':
            case 'date':
            case 'time':
            {
                break;
            }

            case 'email':
            {
                $rule_attrs['is_mayby_empty'] = $type_attrs == ':maybe_empty';
                break;
            }

            case 'ip':
            {
                $rule_attrs['is_long'] = $type_attrs == ':long';
                break;
            }

            default:
            {
                trigger_error( 'Undefined validator rule type ('.$type.') for key ('.$key.')', E_USER_WARNING );
                return false;
            }
        }

        $this->rules[$key] = $rule_attrs;
        return true;
    }

    public function add_callback( $key, $callback_attrs )
    {
        $this->callback_funcs[$key] = $callback_attrs;
        return true;
    }

    public function setnull_by_fixvalue( $key, $fixvalue )
    {
        $this->setnull_by_fixvalue[$key] = $fixvalue;
        return true;
    }

    public function exec( $values )
    {
        $errors = array();
        $result = array();

        foreach( $this->rules as $key => $rule_attrs )
        {
            switch( $rule_attrs['type'] )
            {
                case 'null':
                {
                    $value = null;
                    break;
                }

                case 'integer':
                {
                    $value = (int) trim( $values[$key] );

                    if( $rule_attrs['min'] !== null && $rule_attrs['min'] > $value )
                    {
                        $errors[$key] = SPI::I('lang')->validator->err__out_of_range;
                    }
                    elseif( $rule_attrs['max'] !== null && $rule_attrs['max'] < $value )
                    {
                        $errors[$key] = SPI::I('lang')->validator->err__out_of_range;
                    }
                    break;
                }

                case 'float':
                {
                    $value = trim( $values[$key] );
                    $value = str_replace( ',', '.', $value );
                    $value = (float) $value;

                    if( $rule_attrs['min'] !== null && $rule_attrs['min'] > $value )
                    {
                        $errors[$key] = SPI::I('lang')->validator->err__out_of_range;
                    }
                    elseif( $rule_attrs['max'] !== null && $rule_attrs['max'] < $value )
                    {
                        $errors[$key] = SPI::I('lang')->validator->err__out_of_range;
                    }
                    break;
                }

                case 'string':
                {
                    $value = trim( $values[$key] );

                    if( $rule_attrs['is_exteditor_clean'] === true )
                    {
                        $value = preg_replace( '/<!--([\\s\\S]*?)-->/', '', $value );
                        $value = preg_replace( '/<(meta|link|style)([\\s\\S]*?)\/\1>/', '', $value );
                        $value = trim( $value );
                    }

                    if( $rule_attrs['min_length'] !== null && $rule_attrs['min_length'] > iconv_strlen( $value ) )
                    {
                        $errors[$key] = sprintf( SPI::I('lang')->validator->err__too_short, $rule_attrs['min_length'] );
                    }
                    elseif( $rule_attrs['max_length'] !== null && $rule_attrs['max_length'] < iconv_strlen( $value ) )
                    {
                        $errors[$key] = sprintf( SPI::I('lang')->validator->err__too_long, $rule_attrs['max_length'] );
                    }
                    break;
                }

                case 'date':
                {
                    $value = trim( $values[$key] );

                    if( $value == '' )
                    {
                        $value = null;
                    }
                    else
                    {
                        $value = strtotime( $value );

                        if( $value === false )
                        {
                            $errors[$key] = SPI::I('lang')->validator->err__invalide_date_format;
                        }
                        else
                        {
                            $value = strftime( '%Y-%m-%d', $value );
                        }
                    }
                    break;
                }

                case 'time':
                {
                    $value = trim( $values[$key] );

                    if( $value == '' )
                    {
                        $value = null;
                    }
                    else
                    {
                        if( preg_match( '/^(([0-1][0-9])|(2[0-3])):([0-5][0-9])$/u', $value ) > 0 )
                        {
                            $value .= ':00';
                        }
                        elseif( preg_match( '/^(([0-1][0-9])|(2[0-3])):([0-5][0-9]):([0-5][0-9])$/u', $value ) > 0 )
                        {
                            /* good */
                        }
                        else
                        {
                            $errors[$key] = SPI::I('lang')->validator->err__invalide_time_format;
                        }
                    }
                    break;
                }

                case 'email':
                {
                    $value = trim( $values[$key] );

                    if( $rule_attrs['is_mayby_empty'] === true && $value == '' )
                    {
                        break;
                    }

                    if( preg_match( '/^([_a-z0-9-]+)(\.[_a-z0-9-]+)*@([a-z0-9-]+)(\.[a-z0-9-]+)*(\.[a-z]{2,4})$/iu', $value ) == 0 )
                    {
                        $errors[$key] = SPI::I('lang')->validator->err__invalide_email_format.':'.$rule_attrs['type'];
                    }
                    break;
                }

                case 'select':
                {
                    $value = trim( $values[$key] );

                    if( in_array( $value, $rule_attrs['allow_variants'] ) === false )
                    {
                        $errors[$key] = SPI::I('lang')->validator->err__out_of_list_value;
                    }
                    break;
                }

                case 'multiselect':
                {
                    $value = is_array( $values[$key] ) ? $values[$key] : array();

                    if( $rule_attrs['allow_variants'] !== null )
                    {
                        foreach( $value as $value_one )
                        {
                            if( in_array( $value_one, $rule_attrs['allow_variants'] ) === false )
                            {
                                $errors[$key] = SPI::I('lang')->validator->err__out_of_list_value;
                                break;
                            }
                        }
                    }
                    else { } # don't check!

                    if( isset( $errors[$key] ) === false )
                    {
                        if( $rule_attrs['min_count'] !== null && $rule_attrs['min_count'] > count( $value ) )
                        {
                            $errors[$key] = sprintf( SPI::I('lang')->validator->err__selected_not_enough, $rule_attrs['min_count'] );
                        }
                        elseif( $rule_attrs['max_count'] !== null && $rule_attrs['max_count'] < count( $value ) )
                        {
                            $errors[$key] = sprintf( SPI::I('lang')->validator->err__selected_too_much, $rule_attrs['max_count'] );
                        }
                    }
                    break;
                }

                case 'url':
                {
                    $value = trim( $values[$key] );

                    if( $value && preg_match( '|^http://|ui', $value ) == 0 )
                    {
                        $errors[$key] = SPI::I('lang')->validator->err__invalide_url_format;
                    }
                    break;
                }

                case 'ip':
                {
                    $value = trim( $values[$key] );

                    if( $value )
                    {
                        if( preg_match( '|^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$|u', $value ) == 0 )
                        {
                            $errors[$key] = SPI::I('lang')->validator->err__invalide_ip_format;
                        }
                        elseif( $rule_attrs['is_long'] )
                        {
                            $value = ip2long( $value );
                        }
                    }
                    break;
                }
            }

            $result[$key] = $value;
        }

        //---------------------------------------------------------------------
        // Set null values

        if( is_array( $this->setnull_by_fixvalue ) === true )
        foreach( $this->setnull_by_fixvalue as $key => $value )
        {
            if( isset( $result[$key] ) === true && $result[$key] === $value )
            {
                $result[$key] = null;
            }
        }

        //---------------------------------------------------------------------
        // Exec callbacks

        if( is_array( $this->callback_funcs ) === true )
        foreach( $this->callback_funcs as $key => $callback_attr )
        {
            $object = $callback_attr[0];
            $func   = $callback_attr[1];

            $callback_result = $object->$func( $result[$key], $result );

            if( $callback_result !== true )
            {
                $errors[$key] = $callback_result;
            }
        }

        //---------------------------------------------------------------------

        if( count( $errors ) > 0 )
        {
            return array( false, $errors );
        }

        return array( true, $result );
    }
}
